//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#ifndef __AUDIOCARD_H__
#define __AUDIOCARD_H__
//#define DEBUG_AUDIO
#ifdef DEBUG_AUDIO
#define DBGOUT(x) (x)
#else
#define DBGOUT(x)
#define DBGCHAR(x)
#endif

#define AUDIO_BUFSIZE 0x1000
#define AUDIO_BUFCNT  16

#define MAX_WAIT_TIME 800 // Max time (tick) to wait for recording,tick=10 ms


// Definitions for DMA control
#define DMA_MAP_VALID_MASK  (0x1U << 7)  // Request is mapped to a valid channel indicated by DRCMRx(3:0)

#define DCSR_BUSERRINTR     (0x1U << 0)  // Bus error status bit
#define DCSR_STARTINTR      (0x1U << 1)  // Descriptor fetch status
#define DCSR_ENDINTR        (0x1U << 2)  // finish status
#define DCSR_STOPINTR       (0x1U << 3)  // stopped status
#define DCSR_REQPEND        (0x1U << 8)  // Request Pending (read-only)
#define DCSR_STARTIRQEN     (0x1U << 21) // Enable the start interrupt (when the descriptor is loaded)
#define DCSR_EORSTOPEN       (0x1U << 26) //
#define DCSR_STOPIRQEN       (0x1U << 29) // Enable the stopped interrupt (when the descriptor is done)
#define DCSR_NOFETCH        (0x1U << 30) // Descriptor fetch mode, 0 = fetch
#define DCSR_RUN            (0x1U << 31) // run, 1=start

// the dmcd struct is for documentation
struct dcmdRegBits
{
	unsigned len	     :13;
	unsigned rsv0		 :1;
	unsigned width		 :2;
	unsigned size		 :2;
	unsigned endian		 :1;
	unsigned flybyt	 	 :1;
	unsigned flybys	 	 :1;
	unsigned endirqen    :1;
	unsigned startirqen  :1;
	unsigned rsv1        :5; // May be changed in new documents
	unsigned flowtrg     :1;
	unsigned flowsrc     :1;
	unsigned inctrgadd   :1;
	unsigned incsrcadd   :1;
};

union DmaCmdReg// allow bitfields or masks
{
	volatile struct dcmdRegBits DcmdReg ;
	volatile UInt32 DcmdDword;
} ;

// INTC Register definitions
//
typedef struct
{
    // First set of registers are for controlling for interrupts 0-31
  unsigned long    icip;       // INTC IRQ Pending Register
  unsigned long    icmr;       // INTC Mask Register
  unsigned long    iclr;       // INTC Level Register (IRQ vs FIQ)
  unsigned long    icfp;       // INTC FIQ Pending Register
  unsigned long    icpr;       // INTC Pending Register
  unsigned long    iccr;       // INTC Control Register
  unsigned long    ichp;       // INTC Highest Priority Register
  unsigned long    ipr[32];    // Interrupt Priority Registers [0-31]
    // Registers controlling interrupt signals 32+
  unsigned long    icip2;      // INTC IRQ Pending Register
  unsigned long    icmr2;      // INTC Mask Register
  unsigned long    iclr2;      // INTC Level Register (IRQ vs FIQ)
  unsigned long    icfp2;      // INTC FIQ Pending Register
  unsigned long    icpr2;      // INTC Pending Registers 32+33 valid
    // Second array of IPR registers here  because addresses for [32+]
    //  are discontinuous from IPR [0..31]
    // Space reserved in documents for 32-39 even though 34-39 not used now.
  unsigned long    ipr2[2];    // Interrupt Priority Registers 32,33 valid
  unsigned long    iprRsvd[6]; // Interrupt Priority Registers 34-39, futures
} INTC_REGS, *PINTC_REGS;

#define IRQ_DMAC 25

#define BITS_8_TO_16(x)      ((UInt16)(((Int32) ((UInt8) (x) - 128) ) << 8))
#define BITS_16_TO_8(x)      ((Byte) (((x) >> 8) + 128))

// AudioInital flag
#define AUDIO_ALLOCBUFFER   0x1
#define AUDIO_OPENHARDWARE  0x2

typedef enum {
    WAVEDIR_NOTPREPARED = 0,
    WAVEDIR_PLAYING,
    WAVEDIR_RECORDING,
    WAVEDIR_RESERVED
} WAVEDIR;

typedef enum {
    STATUS_INITIAL = 0,
    STATUS_NORMAL,
    STATUS_BUFFER_FULL,
    STATUS_BUFFER_EMPTY,
    STATUS_RESERVED
} AUDIOSTATUS;

typedef enum {
    WAVEINSOURCE_MAINMIC = 0,
    WAVEINSOURCE_LINE1,
    WAVEINSOURCE_LINE2,
    WAVEINSOURCE_LINEALL,
    WAVEINSOURCE_AUXMIC,
    WAVEINSOURCE_RESERVED
} WAVEINSOURCE;


class CAudioCard : public CDeviceDriver {

    public:
    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

        ECode Flush();

        virtual Boolean  HandleInterrupt(void);

        virtual Int32  Initialize(void);

        virtual void Dispose();

        void AudioInitial(WAVEDIR dir, unsigned long flag);
        void AudioOutClose();
        void AudioInClose();

        UInt32 FillBuffer(const Byte *pBuf, Int32 Size);
        UInt32 GetBuffer(Byte *pBuf, Int32 Size);
        Boolean DmaChOutIsr();
        Boolean DmaChRcvIsr();

        ECode AllocBuffer();
        void FreeBuffer();

        DzMutex   m_lock;
        DzEvent   m_synch;
        Address m_bufVirt;
        Address m_bufPhys;
        Address m_descVirt;
        Address m_descPhys;
        Boolean m_bDmaInProgress;
        Boolean m_nBits;
        UInt32 m_nChannels;
        UInt32 m_nRate;
        UInt32 m_nFillingBufPos;
        UInt32 m_nFillingBufIdx;
        UInt32 m_nTransBufIdx;

        WAVEDIR m_waveDir;
        AUDIOSTATUS m_status;
        WAVEINSOURCE m_waveInSource;
        Boolean m_bUseSpeaker;

        Boolean m_bSendData;

        void (*m_funcWriteCopy)(Byte *pDes, Byte *pSrc, UInt32 cnt);
        void (*m_funcReadCopy)(Byte *pDes, Byte *pSrc, UInt32 cnt);
};

#endif//__AUDIOCARD_H__
